feat(apps): AppsScreen and InspectorView wiring (#1263)#1286
feat(apps): AppsScreen and InspectorView wiring (#1263)#1286
Conversation
Adds the Apps tab as a top-level screen composed of `AppListItem`, `AppDetailPanel`, and `AppRenderer`. The screen is presentational — selection, form values, running, and maximize state are local; data and side effects come in via props and callbacks. InspectorView filters `tools` through `isAppTool` (wrapped in a try/catch so a malformed `_meta.ui.resourceUri` skips one tool instead of dropping every following App), exposes the Apps tab in `ALL_TABS` after Tools, and wires Phase-3 stub callbacks plus a stub bridge factory. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls the sidebar list, search input, "List updated" indicator, and Refresh button out of `AppsScreen` into a dedicated `AppControls` group, mirroring `ToolControls` and `TaskControls`. The Refresh button moves from a full-width row beneath the list to the top-right of the title row (single label "Refresh", matching `TaskControls`). `AppsScreen` keeps the right-pane orchestration (selection, form, running, maximize, header actions) and now delegates the entire sidebar to `AppControls`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds three apps (Cohort Data, Weather Widget, Ops Dashboard) carrying real `_meta.ui.resourceUri` to the demo tools list so the Apps tab has content in the Default story alongside the existing tools. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The parent AppsScreen header already shows the app name, so the panel's own title/icon row rendered the name twice. Remove the title row (and its now-unused imports, styled subcomponents, and the four tests that asserted on title/icon rendering). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The list row now renders just the resource title/name. Audience and priority badges remain visible in the preview/template panels, so the data is still surfaced — just not duplicated in the picker. Drops the now-unused AnnotationBadge import, the badge-only stories, and the badge-rendering test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude review |
|
Claude finished @cliffhall's task in 1m 35s —— View job Code Review
Overall this is a solid, well-tested PR. The two-panel layout is clean, the auto-launch for no-field apps is a nice UX touch, and the try/catch guard on Findings1.
function hasInputFields(tool: Tool): boolean {
return Object.keys(tool.inputSchema.properties ?? {}).length > 0;
}
const hasFields = Object.keys(inputSchema.properties ?? {}).length > 0;Both do exactly the same check. If the definition of "has fields" ever needs to change (e.g. 2. Double dedup guard for re-selecting the same app
onClick={() => {
if (tool.name !== selectedName) onSelectApp(tool.name);
}}
if (name === selectedAppName) return;
3. const LIST_MAX_HEIGHT =
"calc(100vh - var(--app-shell-header-height, 0px) - var(--mantine-spacing-xl) * 2 - 220px)";The 4. The 5. App icon not shown in the detail-panel header
What's working well
|
- Extracts the duplicated `Object.keys(inputSchema.properties ?? {}).length > 0`
check from `AppsScreen` (and the equivalent in `AppDetailPanel`'s
`hasFields`) into a shared `hasInputFields` helper in `toolUtils`,
with tests.
- Renders the selected tool's first icon next to the right-pane header
title in `AppsScreen`, restoring the icon visibility that was lost
when `AppDetailPanel`'s title row was removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for the review! Responses below, in order. 1. 2. Double dedup guard in 3. 4. 5. App icon missing from detail-panel header — fixed in d654cfe. The right-pane
|
|
@claude review |
|
Claude finished @cliffhall's task in 1m 35s —— View job Code Review
Good overall shape. The icon fix and Findings1. The previous review response said: "Both const hasFields = Object.keys(inputSchema.properties ?? {}).length > 0;This is still the inline version — 2.
<AppDetailPanel
tool={selectedTool}
formValues={formValues}
isOpening={false} // ← hardcoded
...
/>
What's working well
|
- AppDetailPanel now actually calls the shared `hasInputFields` helper
instead of inlining the same `Object.keys(...).length > 0` check.
- AppsScreen comments why `isOpening={false}` is hardcoded: the screen
flips to AppRenderer synchronously, so the loading state is unreachable
here — the prop remains for standalone use and Phase 3 wiring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for catching the half-done extraction. 1. 2.
|
|
@claude review |
|
Claude finished @cliffhall's task in 1m 35s —— View job Code Review
Both items from the last round are fully resolved. No new findings — this PR is ready to ship from my perspective. Verified fixes1.
const hasFields = hasInputFields(tool);
2. The comment block at
That's exactly the right documentation for a seam that looks like dead code but is intentionally preserved. Future readers won't be tempted to rip the prop out. Spot check — nothing else caught my eye
Nice work on the follow-ups. LGTM. |
Summary
AppsScreen(clients/web/src/components/screens/AppsScreen/) — two-panel layout that composesAppListItem,AppDetailPanel, andAppRenderer. Sidebar shows search +ListChangedIndicator+ Refresh Apps; right pane swaps between detail (form) and renderer (running) with a Back to Input / Maximize / Close header. Maximize hides the sidebar, and apps without input fields auto-launch on selection.InspectorView: add"Apps"toALL_TABS(right after"Tools"), filtertoolsthroughisAppToolin auseMemo(try/catch around theisAppToolthrow so one malformed_meta.ui.resourceUriskips that tool rather than halting the filter), and pass through stub Phase-3 callbacks plus a stub bridge factory."apps"toInspectorTabinclients/web/src/types/navigation.ts.Stories:
NoSelection,AppSelected,AppRunning,AppRunningMaximized,NoFieldsApp,WithListChanged,Empty.Closes #1263.
Test plan
npm run validate(format, lint, build, unit + coverage)npm run test:storybookAppsScreen.tsxper-file coverage: lines 100% / statements 96.42% / functions 100% / branches 92.5%InspectorView.tsxper-file coverage stays above gate after the new wiring🤖 Generated with Claude Code